#pragma once

#include <string>
#include "DXUT.h"
#include "DXUTcamera.h"
#include "Heightmap.h"
#include "VertexPNT.h"

#define ReleaseCOM(x) { if(x){ x->Release();x = 0; } }

const float INFINITY = FLT_MAX;
const float EPSILON  = 0.001f;

struct AABB 
{
	// Initialize to an infinitely small bounding box.
	AABB()
		: minPt(INFINITY, INFINITY, INFINITY),
		maxPt(-INFINITY, -INFINITY, -INFINITY){}

	D3DXVECTOR3 center()
	{
		return 0.5f*(minPt+maxPt);
	}

	D3DXVECTOR3 minPt;
	D3DXVECTOR3 maxPt;
};

using namespace std;

class Terrain
{
public:
	
	Terrain(UINT vertRows, UINT vertCols, float dx, float dz, 
		wstring heightmap, wstring tex0, wstring tex1, 
		wstring tex2, wstring blendMap, float heightScale, 
		float yOffset);
	~Terrain();

	DWORD getNumTriangles();
	DWORD getNumVertices();

	float getWidth();
	float getDepth();

	void onCreateDevice(IDirect3DDevice9 *pd3dDevice);
	void onResetDevice(IDirect3DDevice9 *pd3dDevice);
	void onLostDevice();
	void onDestoryDevice();

	// (x, z) relative to terrain's local space.
	float getHeight(float x, float z);

	void setDirToSunW(const D3DXVECTOR3& d);

	void draw(const D3DXMATRIX& viewProj);

private:
	void buildGeometry(IDirect3DDevice9 *pd3dDevice);
	void buildSubGridMesh(IDirect3DDevice9 *pd3dDevice, RECT& R, VertexPNT* gridVerts); 
	void buildEffect(IDirect3DDevice9 *pd3dDevice);
	void GenTriGrid(int numVertRows, int numVertCols,
		float dx, float dz, 
		const D3DXVECTOR3& center, 
		std::vector<D3DXVECTOR3>& verts,
		std::vector<DWORD>& indices);

private:
	Heightmap mHeightmap;

	vector<ID3DXMesh*> mSubGridMeshes;
	vector<AABB> mSubGridBndBoxes;

	DWORD mVertRows;
	DWORD mVertCols;

	float mWidth;
	float mDepth;

	float mDX;
	float mDZ;

	wstring mHeightMapName;
	wstring mTexName0;
	wstring mTexName1;
	wstring mTexName2;
	wstring mBlendMapName;

	float mHeightScale;
	float mHeightOffset;

	IDirect3DTexture9* mTex0;
	IDirect3DTexture9* mTex1;
	IDirect3DTexture9* mTex2;
	IDirect3DTexture9* mBlendMap;
	ID3DXEffect*       mFX;
	D3DXHANDLE         mhTech;
	D3DXHANDLE         mhViewProj;
	D3DXHANDLE         mhDirToSunW;
	D3DXHANDLE         mhTex0;
	D3DXHANDLE         mhTex1;
	D3DXHANDLE         mhTex2;
	D3DXHANDLE         mhBlendMap;
	
};